package com.retry.task.core.heart;

import java.util.Date;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.retry.task.core.constants.HeartResultEnum;
import com.retry.task.core.constants.RetryTaskServerType;
import com.retry.task.core.constants.RetryTaskURIEnum;
import com.retry.task.core.model.HeartDTO;
import com.retry.task.core.model.base.Result;
import com.retry.task.core.task.RetryTaskProperties;
import com.retry.task.core.utils.HttpClientUtils;
import com.retry.task.core.utils.IpUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author gao.gwq
 * @version 1.0
 * @date 2022/4/25  13:42
 * @Description TODO 心跳发送，发送心跳到服务器证明当前服务还存在，2 秒发送一次 每个服务器都会定时发送心跳
 */
public class HeartBeatService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HeartBeatService.class);

    private RetryTaskProperties taskProperties;

    private RetryTaskProperties getTaskProperties() {
        return taskProperties;
    }

    private void setTaskProperties(RetryTaskProperties taskProperties) {
        this.taskProperties = taskProperties;
    }

    private ScheduledExecutorService scheduledExecutorService;

    private HeartBeatService() {

    }

    public static void initClientHeart(RetryTaskProperties retryTaskProperties) {
        InnerClass.heartService.initHeart(retryTaskProperties);
    }

    private static final class InnerClass {
        private static final HeartBeatService heartService = new HeartBeatService();
    }

    private void initHeart(RetryTaskProperties retryTaskProperties) {
        setTaskProperties(retryTaskProperties);
        boolean enable = taskProperties.isEnable();
        if (enable == false) {
            return;
        }
        checkParam();
        scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
        scheduledExecutorService.scheduleWithFixedDelay(new HeartRunable(taskProperties), 0, 5, TimeUnit.SECONDS);
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                if (scheduledExecutorService != null) {
                    scheduledExecutorService.shutdown();
                }
            }
        }));
    }

    private String[] checkParam() {

        String serverHost = taskProperties.getServerHost();
        if (StringUtils.isEmpty(serverHost)) {
            throw new RuntimeException("serverHost is null or empty ");
        }
        String projectName = taskProperties.getProjectName();
        if (StringUtils.isEmpty(projectName)) {
            throw new RuntimeException("projectName is null or empty ");
        }
        String token = taskProperties.getToken();
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("token is null or empty ");
        }
        String[] serverHostArr = serverHost.split(",");
        /*for (String ipTmp : serverHostArr) {
            boolean flag = IpUtils.isIPLegal(ipTmp);
            if (!flag) {
                throw new RetryTaskRuntimeException(ipTmp + " is not right ");
            }
        }*/
        return serverHostArr;
    }

    private class HeartRunable implements Runnable {

        private RetryTaskProperties taskProperties;

        public HeartRunable(RetryTaskProperties taskProperties) {
            this.taskProperties = taskProperties;
        }

        @Override
        public void run() {

            //LOGGER.info("start heart tick");
            String[] ipArr = taskProperties.getServerHost().split(",");

            for (String uri : ipArr) {
                //如果配置的clientIp为null，则系统会取clientIp
                String realIp = taskProperties.getClientIp();
                if (StringUtils.isEmpty(realIp)) {
                    String ip = IpUtils.getIp();
                    realIp = taskProperties.getClientPre() + ip;
                    if (taskProperties.getClientPort() != null) {
                        realIp = realIp + ":" + taskProperties.getClientPort();
                    }
                }
                HeartDTO heartDTO = buildClientHeart(realIp);
                long startTime = System.currentTimeMillis();
                HeartTickDO heartTickDO = ServerHeartHolder.get(uri);
                try {
                    heartTickDO.setLastHeartTime(new Date());
                    heartTickDO.setServerIp(uri);
                    heartTickDO.setResult(HeartResultEnum.SUCESS.getCode());
                    String realUri = uri + RetryTaskURIEnum.HEART.getUri();
                    heartTickDO.setLastEndHeartTime(new Date());
                    Result resultDTO = HttpClientUtils.postBody(realUri, heartDTO,
                        String.class, UUID.randomUUID().toString());
                    heartTickDO.setTimeCost(System.currentTimeMillis() - startTime);
                    heartTickDO.setHeartNum(heartTickDO.getHeartNum() + 1);
                    if (!resultDTO.isSuccess()) {
                        heartTickDO.setResult(HeartResultEnum.FAIL.getCode());
                    }
                } catch (Exception ex) {
                    heartTickDO.setResult(HeartResultEnum.FAIL.getCode());
                    LOGGER.error("heart error {}", ex.getMessage(), ex);
                }
            }

        }

        private HeartDTO buildClientHeart(String ip) {
            HeartDTO heartDTO = new HeartDTO();
            heartDTO.setClientIp(ip);
            heartDTO.setIsTest(taskProperties.getIsTest());
            heartDTO.setProjectName(taskProperties.getProjectName());
            heartDTO.setToken(taskProperties.getToken());
            heartDTO.setExecuteType(RetryTaskServerType.CLIENT.getType());
            return heartDTO;
        }
    }
}
